package ar.edu.itba.jMEBowling;

import java.util.logging.Logger;

import ar.edu.itba.jMEBowling.levels.Level;
import ar.edu.itba.jMEBowling.scenario.Scenario;
import ar.edu.itba.jMEBowling.scoring.ScoreDisplay;
import ar.edu.itba.jMEBowling.scoring.Scoring;

import com.jme.input.InputHandler;
import com.jme.input.KeyInput;
import com.jme.input.action.InputActionEvent;
import com.jme.input.action.InputActionInterface;
import com.jmex.physics.PhysicsSpace;
import com.jmex.physics.PhysicsUpdateCallback;
import com.jmex.physics.util.SimplePhysicsGame;

public class Runner extends SimplePhysicsGame {

	private static Runner game;
	private static final Logger logger = Logger.getLogger(Runner.class
			.getName());
	private Scenario scenario;
	private GameStatus gameStatus;
	private ShotSpecification shotSpecification;
	private ActionPerformer actionPerformer;
	private InputHandler physicsStepInputHandler;
	private boolean firstShot;
	private GameMenu gameMenu;
	private ScoreDisplay scoreDisplay;
	private boolean allDetails;
	private Scoring scoring;
	private InputHandler inGameInput;
	private InputHandler inMenuInput;
	private boolean inPause;
	private GameStatus beforePause;

	public Runner() {

	}

	public static void main(String[] args) {

		game = new Runner();
		game.setConfigShowMode(ConfigShowMode.ShowIfNoConfig);
		game.start();
	}

	@Override
	protected void simpleInitGame() {
		scenario = new Scenario(display, rootNode, cam, lightState,
				getPhysicsSpace());
		physicsStepInputHandler = new InputHandler();
		getPhysicsSpace().setAutoRestThreshold(0.3f);
		getPhysicsSpace().addToUpdateCallbacks(new PhysicsUpdateCallback() {
			@Override
			public void afterStep(PhysicsSpace space, float time) {

			}

			@Override
			public void beforeStep(PhysicsSpace space, float time) {
				physicsStepInputHandler.update(time);

			}
		});
		inGameInput = input;

		gameMenu = new GameMenu(statNode, display.getWidth(), display
				.getHeight(), this);
		gameMenu.showAllOptions();
		makeControls(inGameInput);
		input = new InputHandler();
		makeControls(input);
		inMenuInput = input;
		actionPerformer = new ActionPerformer(scenario, shotSpecification);
		gameStatus = GameStatus.INMENU;
		firstShot = true;
		allDetails = false;
		scoring = new Scoring();
		scoreDisplay = new ScoreDisplay(statNode, display.getWidth(), display
				.getHeight(), this);
		inPause = false;

	}

	public void createShotSpecification(Level level) {
		shotSpecification = new ShotSpecification(scenario.getCourtInit(),
				scenario.getCourtWidht(), 3, level, rootNode, timer);
	}

	public void changeShotLevel(Level level) {
		shotSpecification.setLevel(level);
	}

	private void makeControls(InputHandler input) {

		input.addAction(new CameraHandler(), InputHandler.DEVICE_KEYBOARD,
				InputHandler.BUTTON_ALL, InputHandler.AXIS_ALL, true);

		input.addAction(new KeyHandler(), InputHandler.DEVICE_KEYBOARD,
				InputHandler.BUTTON_ALL, InputHandler.AXIS_ALL, false);

		input.addAction(new InputActionInterface() {

			@Override
			public void performAction(InputActionEvent evt) {
				game.pause = !game.pause;
			}
		}, InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_P, InputHandler.AXIS_ALL,
				false);

	}

	@Override
	protected void simpleUpdate() {
		if (gameStatus == GameStatus.WAITINGXPOS) {

			if (!rootNode.hasChild(shotSpecification.getShotDirection())) {
				rootNode.attachChild(shotSpecification.getShotDirection());
			}
			if (rootNode.hasChild(scenario.getBowlingBall().getBallNode())) {
				rootNode.detachChild(scenario.getBowlingBall().getBallNode());
			}
			shotSpecification.xMovement();
		} else if (gameStatus == GameStatus.WAITINGXANGLE) {
			shotSpecification.xAngleMovement();
		} else if (gameStatus == GameStatus.WAITINGARMANGLE) {
			shotSpecification.armMovement();
		} else if (gameStatus == GameStatus.WAITINGPOW) {
			shotSpecification.powerSelection();
		} else if (gameStatus == GameStatus.THROWBALL) {
			if (!rootNode.hasChild(scenario.getBowlingBall().getBallNode())) {
				rootNode.attachChild(scenario.getBowlingBall().getBallNode());
			}
			shotSpecification.finishSelection();
			scenario.getBowlingBall().getBallNode().setAffectedByGravity(true);
			scenario.getBowlingBall().shoot(shotSpecification);
			gameStatus = GameStatus.THROWING;
		} else if (gameStatus == GameStatus.THROWING) {
			if (scenario.shootFinished()) {

				gameStatus = GameStatus.THROWFINISHED;
			}
		} else if (gameStatus == GameStatus.THROWFINISHED) {

			firstShot = scenario.shotAnalize(firstShot, scoring);
			if (firstShot) {
				scoreDisplay.update(scoring);
			}
			shotSpecification.reset();
			if (scenario.gameFinish(scoring)) {
				gameStatus = GameStatus.INMENU;
				input = inMenuInput;
				gameMenu.showAllOptions(scoring.getFinalResults());
				firstShot = true;
				allDetails = false;
				scoring = new Scoring();
				scoreDisplay.reset();
				inPause = false;

			} else {
				gameStatus = GameStatus.WAITINGXPOS;
			}
		}
		// System.out.println("Status " + gameStatus);
	}

	private class KeyHandler implements InputActionInterface {
		@Override
		public void performAction(InputActionEvent evt) {
			gameStatus = actionPerformer.performAction(gameStatus, evt, game);
		}
	}

	public static Runner getGame() {
		return game;
	}

	public static void setGame(Runner game) {
		Runner.game = game;
	}

	public Scenario getScenario() {
		return scenario;
	}

	public void setScenario(Scenario scenario) {
		this.scenario = scenario;
	}

	public GameStatus getGameStatus() {
		return gameStatus;
	}

	public void setGameStatus(GameStatus gameStatus) {
		this.gameStatus = gameStatus;
	}

	public ShotSpecification getShotSpecification() {
		return shotSpecification;
	}

	public void setShotSpecification(ShotSpecification shotSpecification) {
		this.shotSpecification = shotSpecification;
	}

	public ActionPerformer getActionPerformer() {
		return actionPerformer;
	}

	public void setActionPerformer(ActionPerformer actionPerformer) {
		this.actionPerformer = actionPerformer;
	}

	public InputHandler getPhysicsStepInputHandler() {
		return physicsStepInputHandler;
	}

	public void setPhysicsStepInputHandler(InputHandler physicsStepInputHandler) {
		this.physicsStepInputHandler = physicsStepInputHandler;
	}

	public boolean isFirstShot() {
		return firstShot;
	}

	public void setFirstShot(boolean firstShot) {
		this.firstShot = firstShot;
	}

	public GameMenu getGameMenu() {
		return gameMenu;
	}

	public void setGameMenu(GameMenu gameMenu) {
		this.gameMenu = gameMenu;
	}

	public static Logger getLogger() {
		return logger;
	}

	public boolean isAllDetails() {
		return allDetails;
	}

	public void setAllDetails(boolean allDetails) {
		this.allDetails = allDetails;
	}

	public void enableCamera() {
		input = inGameInput;

	}

	public void pause() {
		game.pause = !game.pause;
	}

	public ScoreDisplay getScoreDisplay() {
		return scoreDisplay;
	}

	public void setScoreDisplay(ScoreDisplay scoreDisplay) {
		this.scoreDisplay = scoreDisplay;
	}

	public Scoring getScoring() {
		return scoring;
	}

	public void setScoring(Scoring scoring) {
		this.scoring = scoring;
	}

	public InputHandler getInGameInput() {
		return inGameInput;
	}

	public void setInGameInput(InputHandler inGameInput) {
		this.inGameInput = inGameInput;
	}

	public boolean isInPause() {
		return inPause;
	}

	public void setInPause(boolean inPause) {
		this.inPause = inPause;
	}

	public GameStatus getBeforePause() {
		return beforePause;
	}

	public void setBeforePause(GameStatus beforePause) {
		this.beforePause = beforePause;
	}

	public void setMenuCamera() {
		input = inMenuInput;
	}

}
